<?php
/**
 * Note: 推广数据
 */
namespace App\Http\Controllers\Admin;

use App\Models\Game\Center\AppSourceCpa;
use App\Models\Game\Center\SourceLtv;
use App\Models\Game\Center\SourceLtvDetail;
use App\Models\Mongo\DailyLog\DayStat;
use App\Models\Mongo\DailyLog\HourStat;
use App\Models\Mongo\DailyLog\MonthStat;
use App\Traits\AdminTrait;
use Carbon\Carbon;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;

class SpreadDataController extends BackendController
{
    use AdminTrait;

    /**
     * 数据报表 整合
     * @param Request $request
     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
     */
    public function dayStat(Request $request)
    {
        if (!$request->day) {
            $request->day = [
                now()->subWeek()->toDateString(),
                now()->subDay()->toDateString(),
            ];
        } else {
            $request->day = array_map(function ($v) {
                return date('Y-m-d', $v);
            }, $request->day);
        }

        $lists = DayStat::ofFieldNumeric('source', 0)->ofDateRange('day', $request->day)->orderBy('day')->get();
        $days = $lists->pluck('day')->map(function ($v) {
            return str_replace('-', '', $v);
        })->toArray();

        $footer = [];

        return JsonResource::collection([
            'data' => $lists,
            'footer' => $footer,
        ]);
    }

    /**
     * 日报表
     * @param Request $request
     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
     */
    public function daily(Request $request)
    {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);

        $lists = DayStat::ofFieldNumeric('source', $sources)
            ->where('source', '<>', 0)
            ->ofDateRange('day', $request->day)
            ->ofField('spreadUser', $request->spreadUser)
            ->orderBy('source')
            ->orderBy('day')
            ->with('appSource:id,type')
            ->paginate((int) $request->pageSize);

        return JsonResource::collection($lists);
    }

    /**
     * 日报表
     * @param Request $request
     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
     */
    public function dailyAgent(Request $request)
    {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);

        $lists = DayStat::ofFieldNumeric('source', $sources)
            ->where('source', '<>', 0)
            ->ofDateRange('day', $request->day)
            ->ofField('spreadUser', $request->spreadUser)
            ->where('cpaCostFormula', '>', '')
            ->orderBy('source')
            ->orderBy('day')
            ->select(['source', 'day', 'registerUser', 'pay', 'payAlipay', 'withdraw', 'cpaCostFormula', 'cpaCost', 'payFirst', 'payFirstUser', 'thirdExchange'])
            ->paginate((int) $request->pageSize);

        foreach ($lists->items() as $item) {
            $item->setAppends(['payChannelFee', 'spreadCost']);
            // 公式一般为 (充值-权益)*0.7的形式, 最后乘的是结算比例
            $item['formula'] = substr($item['cpaCostFormula'], 0, strrpos($item['cpaCostFormula'], '*'));
            $item['scale'] = substr($item['cpaCostFormula'], strrpos($item['cpaCostFormula'], '*')+1);
            $formula = str_replace('$', '$item->', AppSourceCpa::convertFormula($item['formula']));
            $pay = 0;
            eval("\$pay = {$formula};");
            $item['pay1'] = $pay;
            $item['spreadCost'] = $item->spreadCost;
        }

        return JsonResource::collection($lists);
    }

    /**
     * 子代理 接口相同, 仅页面显示不同
     * @param Request $request
     * @return AnonymousResourceCollection
     */
    public function dailyAgentSub(Request $request)
    {
        return $this->dailyAgent($request);
    }

    /**
     * 日报表 代理
     * 只看注册
     * @param Request $request
     * @return \Illuminate\Support\Collection
     */
    public function dailyAgentReg(Request $request)
    {
        // 移除无用字段
        $resource = $this->dailyAgent($request);
        $hiddens = array_values(array_diff((new DayStat())->getFillable(), ['day', 'source', 'registerUser']));
        $resource->collection->map(function(JsonResource $collect) use (&$hiddens) {
            $collect->resource->setAppends([])->makeHidden($hiddens);
        });
        return $resource;
    }

    /**
     * 日报表 代理
     * 只看注册 (伪装激活)
     * @param Request $request
     * @return AnonymousResourceCollection|\Illuminate\Support\Collection
     */
    public function dailyAgentReg2Active(Request $request)
    {
        return $this->dailyAgentReg($request);
    }

    /**
     * 获取优化师列表
     * @param Request $request
     * @return Application|ResponseFactory|Response
     */
    public function getSpreadUsers(Request $request)
    {
        $user1 = DayStat::where('spreadUser', '>', '')->raw()->distinct('spreadUser');
        $user2 = MonthStat::where('spreadUser', '>', '')->raw()->distinct('spreadUser');
        $spreadUsers = array_filter(array_unique(array_merge($user1, $user2)));
        return responseData($spreadUsers);
    }

    /**
     * 日报表更新
     * 目前只更新推广员相关信息
     * @param Request $request
     * @param $id
     * @return Application|ResponseFactory|Response
     */
    public function dailySimpleUpdate(Request $request, $id)
    {
        $model = DayStat::find($id);

        if (!$model->update($request->all())) return responseException(__('web.failed'));

        // 推广员同步到sourceLtv, sourceLtvDetail表
        SourceLtv::where('day', $model->day)->where('source', $model->source)->update([
            'spreadUser' => $model->spreadUser ?: '',
        ]);
        SourceLtvDetail::where('regDay', $model->day)->where('source', $model->source)->update([
            'spreadUser' => $model->spreadUser ?: '',
        ]);
        return responseMessage(__('web.success'));
    }

    /**
     * 更新日统计数据
     * 目前只更新cpaCost
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function dailyBatchUpdate(Request $request)
    {
        $days = [];
        $monthSources = [];
        // 更新具体渠道数据
        foreach ($request->data as $data) {
            if (empty($data['day']) || empty($data['source'])) continue;
            $days[] = $data['day'];
            DayStat::where('day', $data['day'])->where('source', (int) $data['source'])->update([
                'cpaCost' => (int) ($data['cpaCost'] * 100),
            ]);
            // 同步到SourceLtv
            SourceLtv::where('day', $data['day'])->where('source', $data['source'])->update([
                'cpaCost' => (int) ($data['cpaCost'] * 100),
            ]);

            // 不同月份更新的渠道数据
            $month = Carbon::parse($data['day'])->format('Y-m');
            $monthSources[$month][] = (int) $data['source'];
        }
        $days = array_unique($days);

        // 更新 source = 0数据
        foreach ($days as $day) {
            $dayCpaCost = DayStat::where('day', $day)->where('source', '>', 0)->sum('cpaCost');

            // 更新日报表
            DayStat::where('day', $day)->where('source', 0)->update(['cpaCost' => (int) $dayCpaCost]);
            // 更新SourceLtv
            SourceLtv::where('day', $day)->where('source', 0)->update(['cpaCost' => (int) $dayCpaCost]);
        }

        // 更新月报推广费
        foreach ($monthSources as $month => $sources) {
            $sources = array_unique($sources);
            $m = Carbon::parse($month);

            // 指定渠道
            foreach ($sources as $source) {
                $cpaCost = DayStat::whereBetween('day', [$m->copy()->startOfMonth()->toDateString(), $m->copy()->endOfMonth()->toDateString()])
                    ->where('source', $source)
                    ->sum('cpaCost');
                MonthStat::where('month', $month)->where('source', $source)->update(['cpaCost' => (int) $cpaCost]);
            }
            // source = 0
            $cpaCost = MonthStat::where('month', $month)->where('source', '>', 0)->sum('cpaCost');
            MonthStat::where('month', $month)->where('source', 0)->update(['cpaCost' => (int) $cpaCost]);
        }
        return responseMessage();
    }

    /**
     * 日报表 汇总
     * @param Request $request
     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
     */
    public function dailyAll(Request $request)
    {
        // 指定单渠道 || 未做筛选
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);
        if (count($sources) === 1 || (!$sources && !$request->spreadUser)) {
            $lists = DayStat::ofDateRange('day', $request->day)
                ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ?'': 0))
                ->ofField('spreadUser', $request->spreadUser)
                ->orderBy('day')
                ->get();
            return JsonResource::collection($lists);
        }

        $lists = (new DayStat())->getDataBySource($sources?:[], $request->spreadUser?:[], $request->day);

        return JsonResource::collection($lists);
    }

    /**
     * 月报详表 不合并渠道
     * @param Request $request
     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
     */
    public function month(Request $request)
    {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);

        $lists = MonthStat::ofFieldNumeric('source', $sources)
            ->ofField('month', $request->month)
            ->ofField('spreadUser', $request->spreadUser)
            ->where('source', '<>', 0)
            ->orderByDesc('month')
            ->orderBy('source')
            ->with('appSource:id,type')
            ->get();
        return JsonResource::collection($lists);
    }

    /**
     * 月报表更新
     * 目前只更新推广员相关信息
     * @param Request $request
     * @param $id
     * @return Application|ResponseFactory|Response
     */
    public function monthSimpleUpdate(Request $request, $id)
    {
        $model = MonthStat::find($id);

        if (!$model->update($request->all())) return responseException(__('web.failed'));
        return responseMessage(__('web.success'));
    }

    /**
     * 更新月统计数据
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function monthBatchUpdate(Request $request)
    {
        $month = null;
        foreach ($request->data as $data) {
            if (empty($data['month']) || empty($data['source'])) continue;
            if (!$month) $month = $data['month'];
            // excel中推广费留空表示清除修正值
            $cpaCostFix = is_numeric($data['cpaCostFix']) ? intval($data['cpaCostFix'] * 100) : null;
            MonthStat::where('month', $data['month'])->where('source', (int) $data['source'])->update([
                'cpaCostFix' => $cpaCostFix,
            ]);
        }
        // 修正渠道0的cpaCost
        $cpaCostFix = MonthStat::where('month', $month)->where('source', '>',0)->get()->sum('spreadCost');
        MonthStat::where('month', $month)->where('source', 0)->update(['cpaCostFix' => (int) $cpaCostFix]);
        return responseMessage();
    }

    /**
     * 月报总表 合并渠道或指定渠道
     * @param Request $request
     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
     */
    public function monthAll(Request $request)
    {
        // 指定单渠道 || 未做筛选
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);
        if (count($sources) === 1 || (!$sources && !$request->spreadUser)) {
            $lists = MonthStat::ofDateRange('month', $request->month)
                ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ?'': 0))
                ->ofField('spreadUser', $request->spreadUser)
                ->orderBy('month')
                ->get();
            return JsonResource::collection($lists);
        }

        $lists = (new MonthStat())->getDataBySource($sources?:[], $request->spreadUser?:[], $request->month);
        return JsonResource::collection($lists);
    }

    /**
     * 渠道LTV
     * @param Request $request
     * @return Collection
     */
    public function sourceLtv(Request $request)
    {
        if ($request->day) {
            $dayStart = date('Y-m-d', $request->day[0]);
            $dayEnd = date('Y-m-d', $request->day[1]);
        } else {
            $dayStart = date('Y-m-d', time()-86400*7);
            $dayEnd = date('Y-m-d', time());
        }

        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type) ?: 0;
        $spreadUser = $request->spreadUser ?: '';

        // 选了渠道, 未选优化师, whereSource
        // 选了渠道, 选了优化师, whereSource, whereSpreadUser
        // 未选渠道, 选择了优化师, whereSpreadUser
        $where = ' AND l.source = 0';
        // 限定渠道
        if ($sources) {
            $where = " AND l.source IN (".implode(',', $sources).")";
        }
        if ($spreadUser) {
            if (!$sources) $where = '';
            $where .= is_array($spreadUser) ? " AND l.spreadUser IN ('".implode("','", $spreadUser)."')" : " AND l.spreadUser='{$spreadUser}'";
        }

        // 基础数据, 充值/权益数据需要根据查询时间来算, 需要联表查询
        $sql = "
SELECT l.day, SUM(l.registerUser) registerUser, SUM(l.loginUser) loginUser, SUM(l.cplCost) cplCost, SUM(l.cpaCost) cpaCost, t.pay, t.withdraw, t.thirdExchange FROM `tb_source_ltv` AS l
LEFT JOIN (
	SELECT regDay, dataDay, SUM(pay) pay, SUM(withdraw) withdraw, SUM(thirdExchange) thirdExchange
	FROM `tb_source_ltv_detail` l
	WHERE regDay BETWEEN '{$dayStart}' AND '{$dayEnd}'
	AND dataDay BETWEEN '{$dayStart}' AND '{$dayEnd}'
    {$where}
	GROUP BY regDay
) AS t
ON l.day = t.regDay
WHERE day BETWEEN '{$dayStart}' AND '{$dayEnd}'
{$where}
GROUP BY l.day
ORDER BY l.day;
";
        $lists = SourceLtv::fromQuery($sql);

        // 若未选择渠道和优化师, 需要清空渠道号0
        if (!$spreadUser && !$sources) $where = '';
        $sql = "
SELECT l.day, COUNT(DISTINCT (CASE WHEN d.pay_cnt>0 THEN d.player_id END)) AS payUser, COUNT(DISTINCT (CASE WHEN d.withdraw_cnt>0 THEN d.player_id END)) AS withdrawUser, COUNT(DISTINCT (CASE WHEN d.third_exchange_cnt>0 THEN d.player_id END)) AS thirdExchangeUser
FROM `tb_source_ltv` l
LEFT JOIN `tb_account_day_stats` d
ON l.day = d.reg_day AND l.source = d.source
WHERE l.day BETWEEN '{$dayStart}' AND '{$dayEnd}'
AND d.day BETWEEN '{$dayStart}' AND '{$dayEnd}'
{$where}
GROUP BY l.day";
        $payWithdrawUsers = SourceLtv::fromQuery($sql)->keyBy('day');

        // 去重的充值人数 去重的权益人数
        // $payWithdrawUsers = CalcService::getPayWithdrawUserCountGroupByRegDay([$dayStart, $dayEnd], [$dayStart, $dayEnd], $sources);

        $lists = $lists->keyBy('day');
        foreach ($lists as $day => &$v) {
            $v['pay'] = intval($v['pay']);
            $v['withdraw'] = intval($v['withdraw']);
            $v['payUser'] = $payWithdrawUsers[$day]->payUser ?? 0;
            $v['withdrawUser'] = $payWithdrawUsers[$day]->withdrawUser ?? 0;
            $v['thirdExchangeUser'] = $payWithdrawUsers[$day]->thirdExchangeUser ?? 0;
        }
        return $lists->values();
    }

    /**
     * 渠道LTV 明细
     * @param Request $request
     * @return array
     */
    public function sourceLtvDetail(Request $request)
    {
        if ($request->day) {
            $dayStart = date('Y-m-d', $request->day[0]);
        } else {
            $dayStart = date('Y-m-d', time()-86400*7);
        }

        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);

        $ltvFields = ['registerUser', 'loginUser', 'pay', 'payUser', 'withdraw', 'withdrawUser', 'thirdExchange', 'thirdExchangeUser', 'cplCost', 'cpaCost'];
        $sumFields = '';
        foreach ($ltvFields as $field) {
            $sumFields .= ",SUM({$field}) {$field}";
        }
        $sumFields = substr($sumFields, 1);
        $sourceLtv = SourceLtv::ofField('day', $dayStart)
            ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ? '' : 0))
            ->ofField('spreadUser', $request->spreadUser)
            ->selectRaw("day, {$sumFields}")
            ->groupBy('day')
            ->first();

        $ltvFields = ['pay', 'payUser', 'withdraw', 'withdrawUser', 'thirdExchange', 'thirdExchangeUser', 'loginUser', ];
        $sumFields = '';
        foreach ($ltvFields as $field) {
            $sumFields .= ",SUM({$field}) {$field}";
        }
        $sumFields = substr($sumFields, 1);
        $lists = SourceLtvDetail::ofField('regDay', $dayStart)
            ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ? '' : 0))
            ->ofDateRange('dataDay', $request->day)
            ->ofField('spreadUser', $request->spreadUser)
            ->selectRaw("regDay, dataDay, DATEDIFF(dataDay, regDay) AS diffDay, {$sumFields}")
            ->groupBy('regDay', 'dataDay')
            ->orderBy('dataDay')
            ->get();

        $spreadCost = $sourceLtv->spread_cost ?? 0;
        $paySum = $withdrawSum = $thirdExchangeSum = 0;
        foreach ($lists as $k => &$v) {
            $v->registerUser = $v->spreadCost = 0;

            $paySum += $v->pay;
            $withdrawSum += $v->withdraw;
            $thirdExchangeSum += $v->thirdExchange;

            if ($k === 0) {
                $v->registerUser = $sourceLtv->registerUser ?? 0;
                $v->spreadCost = $spreadCost;
            }

            // ROI计算
            $v->roi = $spreadCost ? ($paySum - $withdrawSum - $thirdExchangeSum/getCurrencyHbScale(true)) / $spreadCost : 0;
            $v->roiMarket = $spreadCost ? $paySum / $spreadCost : 0;
        }

        // 汇总: 指定注册日期, 在指定日期区间内的, 去重的充值人数/权益人数
        // 选了渠道, 未选优化师, whereSource
        // 选了渠道, 选了优化师, whereSource, whereSpreadUser
        // 未选渠道, 选择了优化师, whereSpreadUser
        $where = ' ';
        if ($sources) {
            $where = " AND l.source IN (".implode(',', $sources).")";
        }
        if ($request->spreadUser) {
            if (!$sources) $where = '';
            $where .= is_array($request->spreadUser) ? " AND l.spreadUser IN ('".implode("','", $request->spreadUser)."')" : " AND l.spreadUser='{$request->spreadUser}'";
        }
        $dataDayRange = array_map(fn($v) => date('Y-m-d', $v), $request->day);
        $sql = "
SELECT l.day, COUNT(DISTINCT (CASE WHEN d.pay_cnt>0 THEN d.player_id END)) AS payUser, COUNT(DISTINCT (CASE WHEN d.withdraw_cnt>0 THEN d.player_id END)) AS withdrawUser, COUNT(DISTINCT (CASE WHEN d.third_exchange_cnt>0 THEN d.player_id END)) AS thirdExchangeUser
FROM `tb_source_ltv` l
LEFT JOIN `tb_account_day_stats` d
ON l.day = d.reg_day AND l.source = d.source
WHERE l.day = '{$dataDayRange[0]}'
AND d.day BETWEEN '{$dataDayRange[0]}' AND '{$dataDayRange[1]}'
{$where}";
        $payWithdrawUsers = SourceLtv::fromQuery($sql);

        // 去重的充值人数 去重的权益人数
        // $payWithdrawUsers = CalcService::getPayWithdrawUserCountGroupByRegDay([$dayStart, $dayStart], $dataDayRange, $request->source ?: 0);
        // AccountDayStat::where('reg_day', $dayStart)->d();
        $footer['payUser'] = $payWithdrawUsers->first()->payUser ?? 0;
        $footer['withdrawUser'] = $payWithdrawUsers->first()->withdrawUser ?? 0;
        $footer['thirdExchangeUser'] = $payWithdrawUsers->first()->thirdExchangeUser ?? 0;

        return [
            'data' => $lists,
            'footer' => $footer,
        ];
    }

    /**
     * 计算渠道ROI
     * TODO CPL推广费没有进行累加, 后期可对每天的CPL费用进行累计, 并追加到主表, 这边代码不需要动
     * @param Request $request
     * @return array
     */
    public function sourceLtvRoi(Request $request)
    {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);

        $sourceLtvs = SourceLtv::ofDateRange('day', $request->day)
            ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ?'': 0))
            ->ofField('spreadUser', $request->spreadUser)
            ->selectRaw('day, SUM(cplCost) cplCost, SUM(cpaCost) cpaCost')
            ->groupBy('day')
            ->get()
            ->keyBy('day');

        $lists = SourceLtvDetail::ofDateRange('regDay', $request->day)
            ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ?'': 0))
            ->ofDateRange('dataDay', $request->day)
            ->ofField('spreadUser', $request->spreadUser)
            ->selectRaw('regDay, dataDay, SUM(pay) pay, SUM(payUser) payUser, SUM(withdraw) withdraw, SUM(withdrawUser) withdrawUser, SUM(thirdExchange) thirdExchange, SUM(thirdExchangeUser) thirdExchangeUser, SUM(loginUser) loginUser, DATEDIFF(dataDay, regDay) AS diffDay')
            ->groupBy('regDay', 'dataDay')
            ->orderBy('regDay')
            ->orderBy('dataDay')
            ->get();

        $arr = [];
        $listsGroupRegDay = $lists->groupBy('regDay');
        foreach ($listsGroupRegDay as $k => $v) {
            if (empty($sourceLtvs[$k])) continue;
            $sourceLtv = $sourceLtvs[$k];

            $data = $v->keyby('diffDay');
            $spreadCost = $sourceLtv->spread_cost ?? 0;
            $paySum = $withdrawSum = $thirdExchangeSum = 0;
            $tmp = [
                'day' => $k,
                'spreadCost' => $spreadCost,
                // 'pay' => $sourceLtv->pay,
                // 'withdraw' => $sourceLtv->withdraw,
                'roi' => [],
                'roiMarket' => [],
            ];
            foreach ($data as $diffDay => $vv) {
                $paySum += $vv->pay;
                $withdrawSum += $vv->withdraw;
                $thirdExchangeSum += $vv->thirdExchange;

                // 对充值和权益进行累加, 进行ROI计算
                if ($request->field === 'roi') {
                    $tmp['roi'][$diffDay] = numberFixed($spreadCost ? ($paySum - $withdrawSum - $thirdExchangeSum/getCurrencyHbScale(true)) / $spreadCost : 0, 4);
                } else {
                    $tmp['roiMarket'][$diffDay] = numberFixed($spreadCost ? $paySum / $spreadCost : 0, 4);
                }
            }
            $arr[] = $tmp;
        }

        $days = [];
        $start = Carbon::createFromTimestamp($request->day[0]);
        $end = Carbon::createFromTimestamp($request->day[1]);
        $dayDiff = $end->diffInDays($start) + 1;

        // 生成 footer
        $footer = [
            'day' => '平均',
            'spreadCost' => array_sum(array_column($arr, 'spreadCost')),
            // 'pay' => array_sum(array_column($arr, 'pay')),
            // 'withdraw' => array_sum(array_column($arr, 'withdraw')),
            'roi' => [],
            'roiMarket' => [],
        ];

        $lists = $lists->sortBy('diffDay')->groupBy('diffDay');

        $paySum = $withdrawSum = $thirdExchangeSum = 0;
        foreach ($lists as $k => $v) {
            // 第一天的时候有推广费
            if ($k === 0) {
                $spreadCost = $sourceLtvs->sum('spreadCost');
            }

            // 充值与权益累加, 与推广费进行计算
            $paySum += $v->sum('pay');
            $withdrawSum += $v->sum('withdraw');
            $thirdExchangeSum += $v->sum('thirdExchange');

            // ROI计算
            if ($request->field === 'roi') {
                $footer['roi'][$k] = numberFixed($spreadCost ? ($paySum - $withdrawSum - $thirdExchangeSum/getCurrencyHbScale(true)) / $spreadCost : 0, 4);
            } else {
                $footer['roiMarket'][$k] = numberFixed($spreadCost ? $paySum / $spreadCost : 0, 4);
            }
        }
        for ($i = 0; $i < $dayDiff; $i++) {
            $day = $start->copy()->addDays($i)->toDateString();
            $days[$day] = $i;
        }
        array_push($arr, $footer);

        return [
            'data' => $arr,
            'days' => $days,
        ];
    }

    /**
     * TODO CPL推广费没有进行累加, 后期可对每天的CPL费用进行累计, 并追加到主表, 这边代码不需要动
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function sourceLtvRoiChart(Request $request)
    {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);

        $spreadCosts = SourceLtv::ofDateRange('day', $request->day)
            ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ?'': 0))
            ->ofField('spreadUser', $request->spreadUser)
            ->get()
            ->groupBy('source')
            ->map(function($v) {
                return $v->sum('spreadCost');
            })->toArray();

        $lists = SourceLtvDetail::ofDateRange('regDay', $request->day)
            ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ?'': 0))
            ->ofDateRange('dataDay', $request->day)
            ->ofField('spreadUser', $request->spreadUser)
            ->selectRaw('*, DATEDIFF(dataDay, regDay) AS diffDay')
            ->orderBy('regDay')
            ->orderBy('dataDay')
            ->get();

        $arr = [];

        // 将lists使用 source, diffDay 进行分组, 得到 ['$source'=> [ '$diffDay1' => [], '$diffDay2'=>[]...]]
        $lists = $lists->sortBy('diffDay')->groupBy(['source', 'diffDay']);

        foreach ($lists as $source => $v) {
            $paySum = $withdrawSum = $thirdExchangeSum = 0;
            $spreadCost = $spreadCosts[$source] ?? 0;
            foreach ($v as $diffDay => $vv) {
                // 充值与权益累加, 与第一日推广费进行计算
                $paySum += $vv->sum('pay');
                $withdrawSum += $vv->sum('withdraw');
                $thirdExchangeSum += $vv->sum('thirdExchange');

                // ROI计算
                $arr[$source]['roi'][$diffDay] = numberFixed($spreadCost ? ($paySum - $withdrawSum - $thirdExchangeSum/getCurrencyHbScale(true)) / $spreadCost : 0, 4);
                $arr[$source]['roiMarket'][$diffDay] = numberFixed($spreadCost ? $paySum / $spreadCost : 0, 4);
            }
        }

        return responseData($arr);
    }

    /**
     * 经营时报
     * @param Request $request
     * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
     */
    public function hour(Request $request): \Illuminate\Http\Resources\Json\AnonymousResourceCollection
    {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);

        // 多个渠道时需要合并
        if ($sources && count($sources)>1) {
            $today = (new HourStat())->getDataBySource($sources, $request->day);
            $today = collect($today)->keyBy('hour')->toArray();

            $yesterday = (new HourStat())->getDataBySource($sources, Carbon::createFromFormat('Y-m-d', $request->day)->subDay()->toDateString());
            $yesterday = collect($yesterday)->keyBy('hour')->toArray();
        } else {
            $today = HourStat::ofField('day', $request->day)
                ->ofFieldNumeric('source', $sources ?: 0)
                ->orderBy('day')
                ->orderByDesc('hour')
                ->get()
                ->keyBy('hour')
                ->toArray();
            $yesterday = HourStat::ofField('day', Carbon::createFromFormat('Y-m-d', $request->day)->subDay()->toDateString())
                ->ofFieldNumeric('source', $sources ?: 0)
                ->orderBy('day')
                ->orderByDesc('hour')
                ->get()
                ->keyBy('hour')
                ->toArray();
        }

        $lists = [];
        foreach ($today as $hour => $v) {
            foreach ($v as $field => $value) {
                if (in_array($field, ['_id', 'day', 'hour'])) continue;
                if (strpos($field, 'All')) {
                    unset($v[$field]);
                    continue;
                }

                // 对比值
                $diffField = "{$field}Diff";
                $v[$diffField] = $value - ($yesterday[$hour][$field] ?? 0);

                // 旧值
                $oldField = "{$field}Old";
                $v[$oldField] = $yesterday[$hour][$field] ?? 0;
            }

            // 增加isset做兼容
            if (isset($v['hbToBulletCost'])) $v['hbToBulletCost'] /= getCurrencyHbScale();
            if (isset($v['hbToBulletCostDiff'])) $v['hbToBulletCostDiff'] /= getCurrencyHbScale();
            if (isset($v['hbToBulletCostOld'])) $v['hbToBulletCostOld'] /= getCurrencyHbScale();
            $lists[] = $v;
        }
        return JsonResource::collection($lists);
    }

    /**
     * 时报表 - 简单版 独立路由
     * @param Request $request
     * @return AnonymousResourceCollection
     */
    public function hourSimple(Request $request)
    {
        return $this->hour($request);
    }

    /**
     * 经营汇总
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function operateTotal(Request $request)
    {
        $request->validate([
            'day' => 'required|date',
        ]);

        $timeRange = [
            Carbon::createFromFormat('Y-m-d', $request->day)->startOfDay(),
            Carbon::createFromFormat('Y-m-d', $request->day)->endOfDay(),
        ];
        // 库存盈利
        $stockProfit = StockProfit::ofField('day', $request->day)->first();
        // 日统计
        $dayStat = DayStat::ofField('day', $request->day)->where('source', 0)->first();
        // 场次盈利
        $sceneProfits = SceneProfit::ofDatetimeRange('create_at', $timeRange)->get();
        // 昨日各场次盈利
        $timeRangeOld = array_map(function(Carbon $v) {
            return $v->copy()->subDay();
        }, $timeRange);
        $sceneProfitsOld = SceneProfit::ofDatetimeRange('create_at', $timeRangeOld)->get()->keyBy('gameId');

        $data['pay'] = ($dayStat->pay ?? 0)/100;
        $data['withdraw'] = $dayStat->thirdExchange;
        $data['spreadCost'] = ($dayStat->spreadCost ?? 0)/100;
        $data['stockChange'] = ($stockProfit->ticket_change ?? 0)/getCurrencyTicketScale() + ($stockProfit->bullet_change ?? 0)/getCurrencyBulletScale() + ($stockProfit->hb_change ?? 0)/getCurrencyHbScale();
        // $data['platformProfit'] = $data['pay'] - $data['withdraw'] - $data['spreadCost'] - $data['stockChange'];
        // $data['cashProfit'] = $data['pay'] - $data['withdraw'] - $data['spreadCost'];
        $data['consumeBullet'] = $sceneProfits->sum('consume_bullet_real');
        $data['hb2bullet'] = CurrencyDayStatistics::ofDatetimeRange('create_at', $timeRange)->value('hbToBulletCost');

        $data['hb2bullet'] = abs($data['hb2bullet']/getCurrencyHbScale());
        $data['freeUserStockBullet'] = ($dayStat->freeUserStockBullet ?? 0)/getCurrencyBulletScale();
        $data['freeUserStockHb'] = ($dayStat->freeUserStockHb ?? 0)/getCurrencyHbScale();

        // 对数字进行格式化
        $format = function (int $value): string {
            if ($value > 100000000) {
                $value = bcdiv($value, 100000000, 2) . '亿';
            } else if ($value > 10000) {
                $value = bcdiv($value, 10000, 2) . '万';
            }
            return $value;
        };

        foreach ($data as $key => $val) {
            if (in_array($key, ['consumeBullet', 'withdraw'])) {
                $data[$key] = $format($val);
            } else {
                $data[$key] = '￥ '. humanNumber($val);
            }
        }

        $scenes = Scene::all()->keyBy('id');

        // 各场次盈利
        $data['sceneProfits'] = [];
        foreach ($sceneProfits as $sceneProfit) {
            if (isset($data['sceneProfits'][$sceneProfit->gameId])) continue;
            $v = [
                'gameId' => $sceneProfit->gameId,
                'gameName' => $scenes[$sceneProfit->gameId]['name'] ?? $sceneProfit->gameId,
                'output' => $sceneProfit->consume_bullet_real, // 流水
                'outputOld' => $sceneProfitsOld[$sceneProfit->gameId]->consume_bullet_real ?? 0, // 昨日流水
            ];
            // 新手引导场流水换为策略值
            if ($sceneProfit->game_type === Scene::TYPE_GUIDE) {
                $v['output'] = $sceneProfit->consume_bullet_noviceStrategy;
                $v['outputOld'] = $sceneProfitsOld[$sceneProfit->gameId]->consume_bullet_noviceStrategy ?? 0;
            }
            $v['outputChange'] = $v['outputOld'] ? ($v['output'] - $v['outputOld'])/$v['outputOld'] : 0; // 流水变化
            $v['output'] = $format($v['output']);// 流水转成 x亿
            $v['outputOld'] = $format($v['outputOld']);// 流水转成 x亿
            $data['sceneProfits'][$v['gameId']] = $v;
        }
        usort($data['sceneProfits'], function($a, $b) {
            return $a['gameId'] > $b['gameId'] ? 1 : -1;
        });

        return responseData($data);
    }

    /**
     * 场次流水图表数据
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function sceneConsumeBulletChart(Request $request)
    {
        $request->validate([
            'day' => 'required|date',
            'days' => 'required|numeric|min:5|max:30'
        ]);

        $timeRange = [
            Carbon::createFromFormat('Y-m-d', $request->day)->startOfDay()->subDays($request->days - 1),
            Carbon::createFromFormat('Y-m-d', $request->day)->endOfDay(),
        ];
        $scenes = Scene::all()->keyBy('id');

        // 场次盈利
        $lists = [];
        $totals = [];
        $sceneProfits = SceneProfit::ofDatetimeRange('create_at', $timeRange)->get()->groupBy('gameId');
        foreach ($sceneProfits as $gameId => $gameSceneProfits) {
            $v = [
                'id' => $gameId,
                'name' => $scenes[$gameId]['name'] ?? (string) $gameId,
                'data' => [],
            ];
            foreach ($gameSceneProfits as $gameSceneProfit) {
                $day = $gameSceneProfit->create_at->toDateString();
                $v['data'][$day] = $gameSceneProfit->consume_bullet_real;
                if (empty($totals[$day])) {
                    $totals[$day] = 0;
                }
                $totals[$day] += $gameSceneProfit->consume_bullet_real;
            }
            // 补全剩余天数 防止中间数据丢失后导致后续数据错位
            for ($i = 0; $i < $request->days; $i++) {
                $day = $timeRange[0]->copy()->addDays($i)->toDateString();
                if (!isset($v['data'][$day])) $v['data'][$day] = 0;
                if (!isset($totals[$day])) $totals[$day] = 0;
            }
            // 按日期重新排序
            ksort($v['data']);
            $lists[] = $v;
        }
        ksort($totals);
        array_unshift($lists, [
            'id' => 0,
            'name' => '总流水',
            'data' => $totals,
        ]);

        return responseData($lists);
    }

    /**
     * 注册留存
     * @param Request $request
     * @return array
     */
    public function userKeep(Request $request): array
    {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);

        $ltvFields = ['registerUser', 'loginUser', 'pay', 'payUser', 'withdraw', 'withdrawUser', 'cplCost', 'cpaCost'];
        $sumFields = '';
        foreach ($ltvFields as $field) {
            $sumFields .= ",SUM({$field}) {$field}";
        }
        $sumFields = substr($sumFields, 1);
        $sourceLtvs = SourceLtv::ofDateRange('day', $request->day)
            ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ?'': 0))
            ->ofField('spreadUser', $request->spreadUser)
            ->selectRaw("day, {$sumFields}")
            ->groupBy('day')
            ->get()
            ->keyBy('day');

        $ltvFields = ['pay', 'payUser', 'withdraw', 'withdrawUser', 'loginUser', ];
        $sumFields = '';
        foreach ($ltvFields as $field) {
            $sumFields .= ",SUM({$field}) {$field}";
        }
        $sumFields = substr($sumFields, 1);
        $lists = SourceLtvDetail::ofDateRange('regDay', $request->day)
            ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ?'': 0))
            ->ofField('spreadUser', $request->spreadUser)
            ->ofDateRange('dataDay', $request->day)
            ->selectRaw("regDay, dataDay, DATEDIFF(dataDay, regDay) AS diffDay, {$sumFields}")
            ->groupBy('regDay', 'dataDay')
            ->orderBy('regDay')
            ->orderBy('dataDay')
            ->get();

        $arr = [];
        $listsGroupRegDay = $lists->groupBy('regDay');
        foreach ($listsGroupRegDay as $k => $v) {
            if (empty($sourceLtvs[$k])) continue;
            $sourceLtv = $sourceLtvs[$k];

            $data = $v->keyby('diffDay');
            $tmp = [
                'day' => $k,
                'registerUser' => $sourceLtv->registerUser,
                'keepScale' => [],
            ];

            foreach ($data as $diffDay => $vv) {
                // 活跃人数 / 总注册人数
                $tmp['keepScale'][$diffDay] = numberFixed($sourceLtv->registerUser ? $vv->loginUser / $sourceLtv->registerUser : 0, 4);
            }
            $arr[] = $tmp;
        }

        $days = [];
        $start = Carbon::createFromTimestamp($request->day[0]);
        $end = Carbon::createFromTimestamp($request->day[1]);
        $dayDiff = $end->diffInDays($start) + 1;

        for ($i = 0; $i < $dayDiff; $i++) {
            $day = $start->copy()->addDays($i)->toDateString();
            $days[$day] = $i;
        }

        // 移除无用数据, 减小数据包大小
        $arr = array_map(function($v) {
            unset($v['pay'], $v['withdraw'], $v['spreadCost']);
            return $v;
        }, $arr);

        return [
            'data' => $arr,
            'days' => $days,
        ];
    }

    /**
     * 用户付费留存
     * @param Request $request
     * @return array
     */
    public function userPayKeep(Request $request)
    {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);

        $ltvFields = ['registerUser', 'loginUser', 'pay', 'payUser', 'withdraw', 'withdrawUser', 'cplCost', 'cpaCost'];
        $sumFields = '';
        foreach ($ltvFields as $field) {
            $sumFields .= ",SUM({$field}) {$field}";
        }
        $sumFields = substr($sumFields, 1);
        $sourceLtvs = SourceLtv::ofDateRange('day', $request->day)
            ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ?'': 0))
            ->ofField('spreadUser', $request->spreadUser)
            ->selectRaw("day, {$sumFields}")
            ->groupBy('day')
            ->get()
            ->keyBy('day');

        $dayStart = Carbon::createFromTimestamp($request->day[0]);
        $dayEnd = Carbon::createFromTimestamp($request->day[1]);

        $where = '';
        if ($sources) $where .=  " AND source IN (".implode(',', $sources).")";

        $sql = "
SELECT COUNT(DISTINCT user_id) AS loginUser, register_day, day, DATEDIFF(day, register_day) AS diffDay
FROM `tb_actions`
WHERE user_id IN (
	SELECT userId
	FROM `tb_account_profit`
	WHERE `created_at` BETWEEN '{$dayStart->startOfDay()->toDateTimeString()}'
    AND '{$dayEnd->endOfDay()->toDateTimeString()}'
    {$where}
    AND `sum_pay` > 0
)
AND day BETWEEN {$dayStart->format('Ymd')} AND {$dayEnd->format('Ymd')}
AND register_day BETWEEN {$dayStart->format('Ymd')} AND {$dayEnd->format('Ymd')}
{$where}
AND type = 1
AND register_day > 0
GROUP BY register_day, day
ORDER BY register_day, day
";
        $lists = DB::connection('gameCenter')->select($sql);
        $lists = array_map(fn($v) => (array)$v, $lists);

        // 截止目前的 不同注册日期充值大于0的用户数量
        $payUsers = AccountProfit::ofDatetimeRange('created_at', $request->day)
            ->ofFieldNumeric('source', $sources)
            ->where('sum_pay', '>', 0)
            ->selectRaw('DATE(created_at) AS regDay, COUNT(id) AS cnt')
            ->groupBy('regDay')
            ->get()
            ->pluck('cnt', 'regDay');

        $days = [];
        $dayDiff = $dayEnd->diffInDays($dayStart) + 1;

        for ($i = 0; $i < $dayDiff; $i++) {
            $day = $dayStart->copy()->addDays($i)->toDateString();
            $days[$day] = $i;
        }

        $arr = [];
        $collects = collect($lists)->groupBy('register_day');

        foreach ($collects as $regDay => $collect) {
            $regDay = date('Y-m-d', strtotime($regDay));
            if (empty($sourceLtvs[$regDay])) continue;
            $sourceLtv = $sourceLtvs[$regDay];

            $tmp = [
                'day' => $regDay,
                'registerUser' => $sourceLtv->registerUser,
                'payUser' => $payUsers[$regDay] ?? 0, // 截止目前累计付费人数
                'payScale' => [],
            ];

            $collect = $collect->keyBy('diffDay');
            $firstDayLoginUser = $collect->first()['loginUser'] ?? 0;
            for ($i = 0; $i < $dayDiff; $i++) {
                $tmp['payScale'][$i] = $firstDayLoginUser ? ($collect[$i]['loginUser']??0)/$firstDayLoginUser : 0;
            }

            $arr[] = $tmp;
        }

        return [
            'data' => $arr,
            'days' => $days,
        ];
    }

    public function userPayRegister(Request $request)
    {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->sourceType);
        $ltvFields = ['registerUser'];
        $sumFields = '';
        foreach ($ltvFields as $field) {
            $sumFields .= ",SUM({$field}) {$field}";
        }
        $sumFields = substr($sumFields, 1);
        $sourceLtvs = SourceLtv::ofDateRange('day', $request->day)
            ->ofFieldNumeric('source', $sources ?: ($request->spreadUser ? '' : 0))
            ->ofField('spreadUser', $request->spreadUser)
            ->selectRaw("day, {$sumFields}")
            ->groupBy('day')
            ->get()
            ->keyBy('day');

        $dayStart = Carbon::createFromTimestamp($request->day[0]);
        $dayEnd = Carbon::createFromTimestamp($request->day[1]);
        $now = Carbon::now();

        $where = '';
        if ($sources) $where .=  " AND source IN (".implode(',', $sources).")";

        $sql = "
            SELECT
                day, register_day,
                COUNT(DISTINCT user_id) AS loginUser,  DATEDIFF(day, register_day) AS diffDay
            FROM `tb_actions`
            WHERE user_id IN (
                SELECT userId
                FROM `tb_account_profit`
                WHERE `created_at` BETWEEN '{$dayStart->startOfDay()->toDateTimeString()}'
                AND '{$dayEnd->endOfDay()->toDateTimeString()}'
                {$where}
                AND `sum_pay` > 0
            )
            AND day BETWEEN {$dayStart->format('Ymd')} AND {$now->format('Ymd')}
            AND register_day BETWEEN {$dayStart->format('Ymd')} AND {$dayEnd->format('Ymd')}
            {$where}
            AND `tb_actions`.type = 1
            GROUP BY register_day, day
            ORDER BY register_day, day
";

        $lists = DB::connection('gameCenter')->select($sql);
        $lists = array_map(fn($v) => (array)$v, $lists);

        // 截止目前的 不同注册日期充值大于0的用户数量
        $payUsers = AccountProfit::ofDatetimeRange('created_at', $request->day)
            ->ofFieldNumeric('source', $sources)
            ->where('sum_pay', '>', 0)
            ->selectRaw('DATE(created_at) AS regDay, COUNT(id) AS cnt')
            ->groupBy('regDay')
            ->get()
            ->pluck('cnt', 'regDay');

        $days = [1, 7, 15, 30];
        $dayDiff = $dayStart->diffInDays($now) + 1;
        foreach ($days as $index => $day) {
            if ($day < $dayDiff) {
                continue;
            }
            $days = array_slice($days, 0, $index);
        }

        $arr = [];
        $collects = collect($lists)->groupBy('register_day');

        foreach ($collects as $regDay => $collect) {
            $regDay = date('Y-m-d', strtotime($regDay));
            if (empty($sourceLtvs[$regDay])) continue;
            $sourceLtv = $sourceLtvs[$regDay];

            $reg = $sourceLtv->registerUser;
            $pay = $payUsers[$regDay] ?? 0;
            $tmp = [
                'day' => $regDay,
                'reg' => (int) $reg,
                'pay' => (int) $pay, // 截止目前累计付费人数
                'ratio' => $reg ? $pay / $reg : 0,
                'retain' => [],
            ];

            $collect = $collect->keyBy('diffDay');
            $firstDayLoginUser = $collect->first()['loginUser'] ?? 0;
            foreach ($days as $day) {
                $index = $day === 1 ? 1 : $day -1;
                if (empty($collect[$day]['loginUser'])) {
                    $tmp['retain'][$day] = '';
                    continue;
                }
                $tmp['retain'][$day] = $firstDayLoginUser ? $collect[$index]['loginUser']/$firstDayLoginUser : "";
            }

            $arr[] = $tmp;
        }

        return [
            'data' => $arr,
            'days' => $days,
        ];
    }
    public function userKeepChart(Request $request)
    {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->sourceType);
        $chartType = $request->chartType ?? 1;
        $dayType = $request->dayType ?? 1;
        $dayType = ($dayType == 1) ? $dayType : ($dayType -1);

        $regStart = Carbon::createFromTimestamp($request->day[0]);
        $regEnd = Carbon::createFromTimestamp($request->day[1]);
        $now = Carbon::now();

        $chartTypeField = "chart_type";

        $actionRow = ", 'all' as $chartTypeField";

        if ($chartType == 2) {
            $actionRow = ", tb_app_sources.type as $chartTypeField";
        } else if ($chartType == 3) {
            $actionRow = ", tb_actions.source as $chartTypeField";
        }


        $where = $spreadUserWhere = $spreadUserJoin = $accountProfitWhere = $accountProfitJoin = '';
        if ($sources) {
            $where .=  " AND tb_actions.source IN (".implode(',', $sources).")";
            $accountProfitWhere = " AND source IN (".implode(',', $sources).")";
        }
        if ($request->spreadUser) {
            $spreadUserJoin = "
                LEFT JOIN (
                    SELECT regDay, source, spreadUser
                    FROM tb_source_ltv_detail
                    WHERE spreadUser <> ''
                    GROUP BY regDay, source, spreadUser
                ) spreadUserTable
                ON tb_actions.source = spreadUserTable.source AND tb_actions.register_day = spreadUserTable.regDay";
            $spreadUserWhere .= " AND spreadUserTable.spreadUser IN (" . implode(',', array_map(function ($item) {
                    return "'$item'";
                }, $request->spreadUser)) . ")";
        }

        $sql = "
            SELECT
                day, register_day,
                COUNT(DISTINCT user_id) AS login_user,
                DATEDIFF(day, register_day) AS diff_day $actionRow
            FROM `tb_actions`
            LEFT JOIN `tb_app_sources` ON `tb_actions`.`source` = `tb_app_sources`.`id`
            {$spreadUserJoin}
            WHERE day BETWEEN {$regStart->format('Ymd')} AND {$now->format('Ymd')}
            AND register_day BETWEEN {$regStart->format('Ymd')} AND {$regEnd->format('Ymd')}
            AND user_id IN (
                SELECT userId
                FROM `tb_account_profit`
                {$accountProfitJoin}
                WHERE `tb_account_profit`.`created_at` BETWEEN '{$regStart->startOfDay()->toDateTimeString()}' AND '{$regEnd->endOfDay()->toDateTimeString()}'
                {$accountProfitWhere}
                AND `tb_account_profit`.`sum_pay` > 0
            )
            {$where}
            {$spreadUserWhere}
            AND `tb_actions`.`type` = 1
            GROUP BY register_day, day, {$chartTypeField}
            HAVING diff_day IN (0, {$dayType})
            ORDER BY register_day, day";
        $days = [];
        $dayDiff = $regStart->diffInDays($regEnd) + 1;
        for ($i = 0; $i < $dayDiff; $i++) {
            $day = $regStart->copy()->addDays($i)->toDateString();
            $days[$day] = 0;
        }

        $actionList = collect(array_map(function ($item) {
            return (array)$item;
        }, DB::connection('gameCenter')->select($sql)))->groupBy(['register_day', $chartTypeField]);

        $chart = [];
        foreach ($actionList as $regDay => $action) {
            $regDay = date('Y-m-d', strtotime($regDay));
            foreach ($action as $channel => $data) {
                $diff = collect($data)->keyBy('diff_day');
                $firstDayLogin = $diff[0]['login_user'] ?? 0;
                if (empty($chart[$channel]['data'])) {
                    $chart[$channel]['data'] = $days;
                }
                $chart[$channel]['data'][$regDay] = $firstDayLogin !== 0 ? ($diff[$dayType]['login_user'] ?? 0) / $firstDayLogin : 0;
            }
        }

        return [
            'data' => $chart,
            'days' => array_keys($days)
        ];
    }

    /**
     * 市场上报分析
     * @param Request $request
     * @return AnonymousResourceCollection
     */
    public function marketReportStat(Request $request) {
        $sources = $this->getQuerySources($request->source, $this->allowSources, $request->source_type);
        $lists = MarketReportStat::ofField("day", $request->day)->ofFieldNumeric('source', $sources)->orderBy('source')->get();
        return JsonResource::collection($lists);
    }
}
